package cn.sanli.manage.utils;


import cn.sanli.manage.utils.text.StrFormatter;
import org.springframework.util.AntPathMatcher;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 字符串工具类
 *
 * @author ruoyi
 */
public class StringUtils extends org.apache.commons.lang3.StringUtils {
    /**
     * 空字符串
     */
    private static final String NULLS = "";

    /**
     * 下划线
     */
    private static final char SEPARATOR = '_';

    /**
     * 获取参数不为空值
     *
     * @param value 要判断的value
     * @param defaultValue 要判断的value
     * @param <T> 泛型
     * @return value 返回值
     */
    public static <T> T nvl(T value, T defaultValue) {
        return value != null ? value : defaultValue;
    }

    /**
     * * 判断一个Collection是否为空， 包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Collection<?> coll) {
        return isNull(coll) || coll.isEmpty();
    }

    /**
     * * 判断一个Collection是否非空，包含List，Set，Queue
     *
     * @param coll 要判断的Collection
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Collection<?> coll) {
        return !isEmpty(coll);
    }

    /**
     * * 判断一个对象数组是否为空
     *
     * @param objects 要判断的对象数组
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Object[] objects) {
        return isNull(objects) || (objects.length == 0);
    }

    /**
     * * 判断一个对象数组是否非空
     *
     * @param objects 要判断的对象数组
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Object[] objects) {
        return !isEmpty(objects);
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return isNull(map) || map.isEmpty();
    }

    /**
     * * 判断一个Map是否为空
     *
     * @param map 要判断的Map
     * @return true：非空 false：空
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }

    /**
     * * 判断一个字符串是否为空串
     *
     * @param str String
     * @return true：为空 false：非空
     */
    public static boolean isEmpty(String str) {
        return isNull(str) || NULLS.equals(str.trim());
    }

    /**
     * * 判断一个字符串是否为非空串
     *
     * @param str String
     * @return true：非空串 false：空串
     */
    public static boolean isNotEmpty(String str) {
        return !isEmpty(str);
    }

    /**
     * * 判断一个对象是否为空
     *
     * @param object Object
     * @return true：为空 false：非空
     */
    public static boolean isNull(Object object) {
        return object == null;
    }

    /**
     * * 判断一个对象是否非空
     *
     * @param object Object
     * @return true：非空 false：空
     */
    public static boolean isNotNull(Object object) {
        return !isNull(object);
    }

    /**
     * * 判断一个对象是否是数组类型（Java基本型别的数组）
     *
     * @param object 对象
     * @return true：是数组 false：不是数组
     */
    public static boolean isArray(Object object) {
        return isNotNull(object) && object.getClass().isArray();
    }

    /**
     * 去空格
     *
     * @param str 字符串
     * @return str
     */
    public static String trim(String str) {
        return (str == null ? "" : str.trim());
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @return 结果
     */
   public static String substring(final String str, int start) {
        // 如果字符串为空，则返回空字符串
        if (str == null) {
            return NULLS;
        }

        // 如果start小于0，则将start转换为str的长度加上start
        if (start < 0) {
            start = str.length() + start;
        }

        // 如果start小于0，则将start设置为0
        if (start < 0) {
            start = 0;
        }
        // 如果start大于str的长度，则返回空字符串
        if (start > str.length()) {
            return NULLS;
        }

        // 返回从start开始的字符串
        return str.substring(start);
    }

    /**
     * 截取字符串
     *
     * @param str   字符串
     * @param start 开始
     * @param end   结束
     * @return 结果
     */
   public static String substring(final String str, int start, int end) {
        // 判断传入的字符串是否为空
        if (str == null) {
            return NULLS;
        }

        // 判断end是否小于0
        if (end < 0) {
            // 若小于0，则将end转换为str的长度加上end
            end = str.length() + end;
        }
        // 判断start是否小于0
        if (start < 0) {
            // 若小于0，则将start转换为str的长度加上start
            start = str.length() + start;
        }

        // 判断end是否大于str的长度
        if (end > str.length()) {
            // 若大于，则将end转换为str的长度
            end = str.length();
        }

        // 判断start是否大于end
        if (start > end) {
            return NULLS;
        }

        // 判断start是否小于0
        if (start < 0) {
            // 若小于0，则将start转换为0
            start = 0;
        }
        // 判断end是否小于0
        if (end < 0) {
            // 若小于0，则将end转换为0
            end = 0;
        }

        // 返回str从start到end的字符串
        return str.substring(start, end);
    }

    /**
     *
     * @param template 文本模板，被替换的部分用 {} 表示
     * @param params   参数值
     * @return 格式化后的文本
     */
   // 定义一个静态方法，用于格式化字符串，参数为模板字符串和参数数组
   public static String format(String template, Object... params) {
        // 如果参数数组为空或者模板字符串为空，则直接返回模板字符串
        if (isEmpty(params) || isEmpty(template)) {
            return template;
        }
        // 使用StrFormatter类的format方法格式化字符串
        return StrFormatter.format(template, params);
    }

    /**
     * 下划线转驼峰命名
     *
     * @param str 字符串
     * @return str
     */
   public static String toUnderScoreCase(String str) {
        if (str == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        // 前置字符是否大写
        boolean preCharIsUpperCase;
        /*
         当前字符是否大写
         下一字符是否大写
        */
        boolean nexteCharIsUpperCase = true;
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (i > 0) {
                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
            } else {
                preCharIsUpperCase = false;
            }

            boolean curreCharIsUpperCase = Character.isUpperCase(c);

            if (i < (str.length() - 1)) {
                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
            }

            // 当前字符和下一个字符都是大写，且当前字符不是大写，则添加下划线
            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase) {
                sb.append(SEPARATOR);
            // 当前字符不是大写，且下一个字符是大小写，则添加下划线
            } else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase) {
                sb.append(SEPARATOR);
            }
            // 将当前字符转换为小写
            sb.append(Character.toLowerCase(c));
        }

        return sb.toString();
    }

    /**
     * 是否包含字符串
     *
     * @param str  验证字符串
     * @param strs 字符串组
     * @return 包含返回true
     */
   public static boolean inStringIgnoreCase(String str, String... strs) {
        // 判断传入的字符串是否在字符串数组中
        if (str != null && strs != null) {
            // 遍历字符串数组
            for (String s : strs) {
                // 判断传入的字符串是否在字符串数组中的字符串中，并且忽略大小写
                if (str.equalsIgnoreCase(trim(s))) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。 例如：HELLO_WORLD - HelloWorld
     *
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String convertToCamelCase(String name) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains("_")) {
            // 不含下划线，仅将首字母大写
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
        // 用下划线将原始字符串分割
        String[] camels = name.split("_");
        for (String camel : camels) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camel.isEmpty()) {
                continue;
            }
            // 首字母大写
            result.append(camel.substring(0, 1).toUpperCase());
            result.append(camel.substring(1).toLowerCase());
        }
        return result.toString();
    }

    /**
     * 驼峰式命名法 例如：user_name - userName
     *
     * @param s 字符串
     * @return string
     */
   public static String toCamelCase(String s) {
        // 如果s为空，返回null
        if (s == null) {
            return null;
        }
        // 将s转换为小写
        s = s.toLowerCase();
        // 创建一个StringBuilder对象，长度为s的长度
        StringBuilder sb = new StringBuilder(s.length());
        // 定义一个变量upperCase，用于判断是否转换为大写
        boolean upperCase = false;
        // 遍历s
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);

            // 如果c为分隔符，则将upperCase设置为true
            if (c == SEPARATOR) {
                upperCase = true;
            // 如果upperCase为true，则将c转换为大写
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            // 否则，将c添加到StringBuilder对象中
            } else {
                sb.append(c);
            }
        }
        // 返回StringBuilder对象转换为字符串
        return sb.toString();
    }

    /**
     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
     *
     * @param str  指定字符串
     * @param strs 需要检查的字符串数组
     * @return 是否匹配
     */
   public static boolean matches(String str, List<String> strs) {
        // 判断传入的字符串是否为空
        if (isEmpty(str) || isEmpty(strs)) {
            return false;
        }
        // 遍历字符串列表
        for (String pattern : strs) {
            // 判断字符串是否匹配
            if (isMatch(pattern, str)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断url是否与规则配置:
     * ? 表示单个字符;
     * * 表示一层路径内的任意字符串，不可跨层级;
     * ** 表示任意层路径;
     *
     * @param pattern 匹配规则
     * @param url     需要匹配的url
     * @return 判断值
     */
   public static boolean isMatch(String pattern, String url) {
        // 创建AntPathMatcher对象
        AntPathMatcher matcher = new AntPathMatcher();
        // 调用match方法，传入pattern和url，返回匹配结果
        return matcher.match(pattern, url);
    }

    @SuppressWarnings("unchecked")
    public static <T> T cast(Object obj) {
        // 将Object类型转换为T类型
        return (T) obj;
    }

    /*
     *  计算字符串的 hash值 ,计算速度是227MB/s
     * */
    public static String hashKeyForDisk(String key) {
        String cacheKey;
        try {
            // 获取MD5加密算法实例
            final MessageDigest mDigest = MessageDigest.getInstance("MD5");
            // 更新要加密的字符串
            mDigest.update(key.getBytes());
            // 获取加密后的字符串
            cacheKey = bytesToHexString(mDigest.digest());
        } catch (NoSuchAlgorithmException e) {
            // 如果加密算法不存在，则使用key的hashCode作为缓存键
            cacheKey = String.valueOf(key.hashCode());
        }
        return cacheKey;
    }

    private static String bytesToHexString(byte[] bytes) {
        // http://stackoverflow.com/questions/332079
        StringBuilder sb = new StringBuilder();
        for (int i = 0, bytesLength = bytes.length; i < bytesLength; i++) {
            byte aByte = bytes[i];
            String hex = Integer.toHexString(0xFF & aByte);
            if (hex.length() == 1) {
                sb.append('0');
            }
            sb.append(hex);
        }
        return sb.toString();
    }
}